﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ОбработчикиСобытийФормы

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	Если ТипЗнч(Параметры.ЗаблокированныеРеквизиты) = Тип("Массив") Тогда
		ЗаблокированныеРеквизиты = Новый ФиксированныйМассив(Параметры.ЗаблокированныеРеквизиты);
		
	ИначеЕсли ЗначениеЗаполнено(Параметры.ПолноеИмяОбъекта) Тогда
		ЗаблокированныеРеквизиты = Новый ФиксированныйМассив(
			ЗапретРедактированияРеквизитовОбъектов.БлокируемыеРеквизитыОбъекта(
				Параметры.ПолноеИмяОбъекта));
	Иначе
		ЗаблокированныеРеквизиты = Новый ФиксированныйМассив(Новый Массив);
	КонецЕсли;
	
	ДобавляемыеЭлементы = Новый Массив; // Массив из см. НовыеСвойстваЭлементаФормы
	ДобавитьРеквизитыНаФорму(ДобавляемыеЭлементы);
	ДобавитьЭлементыНаФорму(ДобавляемыеЭлементы);
	
	Если Параметры.ГрупповоеИзменениеОбъектов Тогда
		Если ЭтоАдресВременногоХранилища(Параметры.АдресСсылокНаОбъекты) Тогда
			АдресСсылокНаОбъекты = Параметры.АдресСсылокНаОбъекты;
		КонецЕсли;
	ИначеЕсли ЗначениеЗаполнено(Параметры.Ссылка) Тогда
		АдресСсылокНаОбъекты = ПоместитьВоВременноеХранилище(
			ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Параметры.Ссылка),
			УникальныйИдентификатор);
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(АдресСсылокНаОбъекты) Тогда
		Элементы.ФормаПроверитьИспользование.Видимость = Ложь;
	КонецЕсли;
	
	СтандартныеПодсистемыСервер.СброситьРазмерыИПоложениеОкна(ЭтотОбъект);
	
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	
	ИзменитьФлажки(Истина, ЗначениеЗаполнено(ОтмеченныйРеквизит));
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиКомандФормы

&НаКлиенте
Процедура УстановитьФлажки(Команда)
	
	ИзменитьФлажки(Истина);
	
КонецПроцедуры

&НаКлиенте
Процедура СнятьФлажки(Команда)
	
	ИзменитьФлажки(Ложь);
	
КонецПроцедуры

&НаКлиенте
Процедура Проверить(Команда)
	
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ПоискИУдалениеДублей") Тогда
		ПараметрыОткрытия = Новый Структура;
		ПараметрыОткрытия.Вставить("Уникальность", УникальныйИдентификатор);
		МассивСсылок = ПолучитьИзВременногоХранилища(АдресСсылокНаОбъекты);
		МодульПоискИУдалениеДублейКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ПоискИУдалениеДублейКлиент");
		МодульПоискИУдалениеДублейКлиент.ПоказатьМестаИспользования(МассивСсылок, ПараметрыОткрытия);
		Возврат;
	КонецЕсли;
	
	Элементы.Страницы.ТекущаяСтраница = Элементы.ДлительнаяОперация;
	
	ДлительнаяОперация = ОбъектыИспользуются();
	
	ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
	ПараметрыОжидания.ВыводитьОкноОжидания = Ложь;
	
	ОповещениеОЗавершении = Новый ОписаниеОповещения("ПроверитьЗавершение", ЭтотОбъект);
	ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОЗавершении, ПараметрыОжидания);
	
КонецПроцедуры

&НаКлиенте
Процедура РазрешитьРедактирование(Команда)
	
	Результат = Новый Массив;
	
	Для Каждого ДобавленныйРеквизит Из РазблокируемыеРеквизиты Цикл
		Если Не ЭтотОбъект[ДобавленныйРеквизит.Ключ] Тогда
			Продолжить;
		КонецЕсли;
		Для Каждого ИмяРеквизита Из ДобавленныйРеквизит.Значение Цикл
			Результат.Добавить(ИмяРеквизита);
		КонецЦикла;
	КонецЦикла;
	
	Если Не ЗначениеЗаполнено(Результат) Тогда
		ПоказатьПредупреждение(, НСтр("ru = 'Выберите хотя бы один реквизит'"));
		Возврат;
	КонецЕсли;
	
	Закрыть(Результат);
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Возвращаемое значение:
//  Структура:
//   * ЭтоНадпись     - Булево
//   * Имя            - Строка
//   * Заголовок      - Строка
//   * Предупреждение - Строка
//
&НаСервереБезКонтекста
Функция НовыеСвойстваЭлементаФормы()
	
	НовыеСвойства = Новый Структура;
	НовыеСвойства.Вставить("ЭтоНадпись", Ложь);
	НовыеСвойства.Вставить("Имя", "");
	НовыеСвойства.Вставить("Заголовок", "");
	НовыеСвойства.Вставить("Предупреждение", "");
	
	Возврат НовыеСвойства;
	
КонецФункции

&НаСервере
Процедура ДобавитьРеквизитыНаФорму(ДобавляемыеЭлементы)
	
	Если ЗначениеЗаполнено(Параметры.ПолноеИмяОбъекта) Тогда
		БлокируемыеРеквизиты = Новый ФиксированныйМассив(
			ЗапретРедактированияРеквизитовОбъектовСлужебный.БлокируемыеРеквизитыОбъектаИЭлементыФормы(
				Параметры.ПолноеИмяОбъекта));
	Иначе
		БлокируемыеРеквизиты = Новый ФиксированныйМассив(Новый Массив);
	КонецЕсли;
	
	Описание = Новый ТаблицаЗначений;
	Описание.Колонки.Добавить("ИмяРеквизита",            Новый ОписаниеТипов("Строка"));
	Описание.Колонки.Добавить("Представление",           Новый ОписаниеТипов("Строка"));
	Описание.Колонки.Добавить("РедактированиеРазрешено", Новый ОписаниеТипов("Булево"));
	Описание.Колонки.Добавить("БлокируемыеЭлементы",     Новый ОписаниеТипов("Массив"));
	Описание.Колонки.Добавить("ПравоРедактирования",     Новый ОписаниеТипов("Булево"));
	
	Если ТипЗнч(Параметры.ОписаниеБлокируемыхРеквизитов) = Тип("Массив") Тогда
		Для Каждого ОписаниеРеквизита Из Параметры.ОписаниеБлокируемыхРеквизитов Цикл
			ЗаполнитьЗначенияСвойств(Описание.Добавить(), ОписаниеРеквизита);
		КонецЦикла;
	Иначе
		МетаданныеОбъекта = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Параметры.ПолноеИмяОбъекта);
		ЗапретРедактированияРеквизитовОбъектовСлужебный.ЗаполнитьОписаниеБлокируемыхРеквизитов(Описание,
			МетаданныеОбъекта, БлокируемыеРеквизиты, Ложь);
	КонецЕсли;
	
	ДобавляемыеРеквизиты = Новый Массив;
	ДобавленныеРеквизиты = Новый Соответствие;
	СвойстваГрупп = Новый Соответствие;
	ОбщаяНадписьНастроена = Ложь;
	Для Каждого БлокируемыйРеквизит Из БлокируемыеРеквизиты Цикл
		Если ЗначениеЗаполнено(БлокируемыйРеквизит.Группа)
		 Или ЗначениеЗаполнено(БлокируемыйРеквизит.ПредставлениеГруппы) Тогда
			СвойстваГруппы = СвойстваГрупп.Получить(БлокируемыйРеквизит.Группа);
			Если СвойстваГруппы = Неопределено Тогда
				СвойстваГруппы = Новый Структура;
				СвойстваГруппы.Вставить("Представление", БлокируемыйРеквизит.ПредставлениеГруппы);
				СвойстваГруппы.Вставить("Предупреждение", БлокируемыйРеквизит.Предупреждение);
				СвойстваГруппы.Вставить("ПредупреждениеГруппы", БлокируемыйРеквизит.ПредупреждениеГруппы);
				СвойстваГрупп.Вставить(БлокируемыйРеквизит.Группа, СвойстваГруппы);
			КонецЕсли;
		КонецЕсли;
		Если Не ОбщаяНадписьНастроена Тогда
			ОбщаяНадписьНастроена = Истина;
			Если Не ЗначениеЗаполнено(БлокируемыйРеквизит.Имя)
			   И БлокируемыйРеквизит.Группа = "ОбщаяНадпись" Тогда
				Если Не ЗначениеЗаполнено(БлокируемыйРеквизит.ПредставлениеГруппы) Тогда
					Продолжить;
				КонецЕсли;
				ЗаголовокНадписи = БлокируемыйРеквизит.ПредставлениеГруппы;
			Иначе
				ЗаголовокНадписи =
					НСтр("ru = 'Перед изменением реквизитов рекомендуется проверить использование объекта.
					           |Если объект используется, то необходимо оценить последствия изменений.'");
			КонецЕсли;
			СвойстваЭлемента = НовыеСвойстваЭлементаФормы();
			СвойстваЭлемента.ЭтоНадпись = Истина;
			СвойстваЭлемента.Имя = "ОбщаяНадпись";
			СвойстваЭлемента.Заголовок = ЗаголовокНадписи;
			ДобавляемыеЭлементы.Добавить(СвойстваЭлемента);
		КонецЕсли;
		Если ЗаблокированныеРеквизиты.Найти(БлокируемыйРеквизит.Имя) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		ОписаниеРеквизита = Описание.Найти(БлокируемыйРеквизит.Имя, "ИмяРеквизита");
		Если ОписаниеРеквизита = Неопределено
		 Или Не ОписаниеРеквизита.ПравоРедактирования Тогда
			Продолжить;
		КонецЕсли;
		СвойстваГруппы = СвойстваГрупп.Получить(БлокируемыйРеквизит.Группа);
		Если СвойстваГруппы <> Неопределено Тогда
			Если Параметры.ГрупповоеИзменениеОбъектов Тогда
				ПолноеИмяРеквизита = "РазблокируемыйРеквизит" + БлокируемыйРеквизит.Имя;
				ПредставлениеРеквизита = ОписаниеРеквизита.Представление;
				Если ЗначениеЗаполнено(БлокируемыйРеквизит.Предупреждение) Тогда
					ПредупреждениеРеквизита = БлокируемыйРеквизит.Предупреждение;
				Иначе
					ПредупреждениеРеквизита = СвойстваГруппы.Предупреждение;
				КонецЕсли;
			Иначе
				ПолноеИмяРеквизита = "РазблокируемыйРеквизит" + БлокируемыйРеквизит.Группа;
				ПредставлениеРеквизита  = СвойстваГруппы.Представление;
				Если ЗначениеЗаполнено(СвойстваГруппы.ПредупреждениеГруппы) Тогда
					ПредупреждениеРеквизита = СвойстваГруппы.ПредупреждениеГруппы;
				Иначе
					ПредупреждениеРеквизита = СвойстваГруппы.Предупреждение;
				КонецЕсли;
			КонецЕсли;
		Иначе
			ПолноеИмяРеквизита = "РазблокируемыйРеквизит" + БлокируемыйРеквизит.Имя;
			ПредставлениеРеквизита = ОписаниеРеквизита.Представление;
			ПредупреждениеРеквизита = БлокируемыйРеквизит.Предупреждение;
		КонецЕсли;
		Добавленные = ДобавленныеРеквизиты.Получить(ПолноеИмяРеквизита);
		Если Добавленные = Неопределено Тогда
			Если БлокируемыйРеквизит.Имя = Параметры.ОтмеченныйРеквизит Тогда
				ОтмеченныйРеквизит = ПолноеИмяРеквизита;
			КонецЕсли;
			Добавленные = Новый Массив;
			ДобавленныеРеквизиты.Вставить(ПолноеИмяРеквизита, Добавленные);
			ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы(ПолноеИмяРеквизита,
				Новый ОписаниеТипов("Булево"),, ПредставлениеРеквизита));
			СвойстваЭлемента = НовыеСвойстваЭлементаФормы();
			СвойстваЭлемента.ЭтоНадпись = Ложь;
			СвойстваЭлемента.Имя = ПолноеИмяРеквизита;
			СвойстваЭлемента.Предупреждение = ПредупреждениеРеквизита;
			ДобавляемыеЭлементы.Добавить(СвойстваЭлемента);
		КонецЕсли;
		Добавленные.Добавить(БлокируемыйРеквизит.Имя);
	КонецЦикла;
	ИзменитьРеквизиты(ДобавляемыеРеквизиты);
	
	РазблокируемыеРеквизиты = ОбщегоНазначения.ФиксированныеДанные(ДобавленныеРеквизиты);
	
КонецПроцедуры

&НаСервере
Процедура ДобавитьЭлементыНаФорму(ДобавляемыеЭлементы)
	
	ЭлементРодитель = Элементы.Главное;
	ЭлементФлажка = Неопределено;
	
	Для Каждого ДобавляемыйЭлемент Из ДобавляемыеЭлементы Цикл
		Если ДобавляемыйЭлемент.ЭтоНадпись Тогда
			ЭлементНадписи = Элементы.Добавить(ДобавляемыйЭлемент.Имя,
				Тип("ДекорацияФормы"), ЭлементРодитель);
			ЭлементНадписи.Вид = ВидДекорацииФормы.Надпись;
			ЭлементНадписи.Заголовок = ДобавляемыйЭлемент.Заголовок;
			ЭлементНадписи.ЦветТекста = Метаданные.ЭлементыСтиля.ПросроченныеДанныеЦвет.Значение;
			ЭлементНадписи.АвтоМаксимальнаяШирина = Ложь;
		Иначе
			СОтступом = ЭлементФлажка <> Неопределено
				И ЗначениеЗаполнено(ЭлементФлажка.РасширеннаяПодсказка.Заголовок);
			Если СОтступом Тогда
				ГруппаФлажка = Элементы.Добавить("Группа" + ДобавляемыйЭлемент.Имя,
					Тип("ГруппаФормы"), ЭлементРодитель);
				ГруппаФлажка.Вид = ВидГруппыФормы.ОбычнаяГруппа;
				ГруппаФлажка.ОтображатьЗаголовок = Ложь;
				ГруппаФлажка.Отображение = ОтображениеОбычнойГруппы.ОбычноеВыделение;
			Иначе
				ГруппаФлажка = ЭлементРодитель;
			КонецЕсли;
			ЭлементФлажка = Элементы.Добавить(ДобавляемыйЭлемент.Имя,
				Тип("ПолеФормы"), ГруппаФлажка);
			ЭлементФлажка.Вид = ВидПоляФормы.ПолеФлажка;
			ЭлементФлажка.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Право;
			ЭлементФлажка.ПутьКДанным = ДобавляемыйЭлемент.Имя;
			Если ЗначениеЗаполнено(ДобавляемыйЭлемент.Предупреждение) Тогда
				ЭлементФлажка.ОтображениеПодсказки = ОтображениеПодсказки.ОтображатьСверху;
				ЭлементФлажка.РасширеннаяПодсказка.Заголовок = ДобавляемыйЭлемент.Предупреждение;
				ЭлементФлажка.РасширеннаяПодсказка.АвтоМаксимальнаяШирина = Ложь;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

&НаКлиенте
Процедура ИзменитьФлажки(Значение, ТолькоОтмеченный = Ложь)
	
	Для Каждого ТекущийРазблокируемыйРеквизит Из РазблокируемыеРеквизиты Цикл
		Если Не ТолькоОтмеченный
		 Или ТекущийРазблокируемыйРеквизит.Ключ = ОтмеченныйРеквизит Тогда
			ЭтотОбъект[ТекущийРазблокируемыйРеквизит.Ключ] = Значение;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

&НаСервере
Функция ОбъектыИспользуются()
	
	Ссылки = ПолучитьИзВременногоХранилища(АдресСсылокНаОбъекты);
	КоличествоСсылок = Ссылки.Количество();
	
	ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
	ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Разблокирование реквизитов: Проверка использования ссылок на объекты'");
	// Всегда в фоне (очередь заданий в файловом варианте), так как результат не требуется срочно, операция редкая,
	// а блокировать интерфейс выполнением в сеансе избыточно, так как поиск ссылок на объект выполняется долго.
	ПараметрыВыполнения.ЗапуститьВФоне = Истина;
	ПараметрыВыполнения.ОжидатьЗавершение = 0;
	
	Возврат ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения,
		"ОбщегоНазначения.ЕстьСсылкиНаОбъект", Ссылки);
	
КонецФункции

&НаКлиенте
Процедура ПроверитьЗавершение(Результат, Контекст) Экспорт
	
	Элементы.Страницы.ТекущаяСтраница = Элементы.Главное;
	Если Результат = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если Результат.Статус = "Ошибка" Тогда
		ПоказатьПредупреждение(, Результат.КраткоеПредставлениеОшибки);
		Возврат;
	КонецЕсли;
	
	ОбъектыИспользуются = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
	Если ТипЗнч(ОбъектыИспользуются) <> Тип("Булево") Тогда
		ПоказатьПредупреждение(, НСтр("ru = 'Не удалось получить результат проверки, попробуйте еще раз'"));
		Возврат;
	КонецЕсли;
	
	Если ОбъектыИспользуются Тогда
		Если КоличествоСсылок = 1 Тогда
			ТекстСообщения =
				НСтр("ru = 'Объект уже используется в других местах в программе.
				           |Не рекомендуется разрешать редактирование из-за риска рассогласования данных.'");
		Иначе
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Выбранные объекты (%1) уже используются в других местах в программе.
				           |Не рекомендуется разрешать редактирование из-за риска рассогласования данных.'"),
				КоличествоСсылок);
		КонецЕсли;
	Иначе
		Если КоличествоСсылок = 1 Тогда
			ТекстСообщения =
				НСтр("ru = 'Объект еще не используется в других местах в программе.
				           |Можно разрешать редактирование без риска рассогласования данных.'");
		Иначе
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Выбранные объекты (%1) уже используются в других местах в программе.
				           |Можно разрешать редактирование без риска рассогласования данных.'"),
				КоличествоСсылок);
		КонецЕсли;
	КонецЕсли;
	
	ПоказатьПредупреждение(, ТекстСообщения);
	
КонецПроцедуры

#КонецОбласти
